#!/usr/bin/env python3

from switchyard.lib.address import *
from switchyard.lib.packet import *
from switchyard.lib.userlib import *
from random import randint
import time
import struct
'''
def draw_progress(num_pkt, acked_seq, LHS, RHS):
    upper = ""
    lower = ""
    for i in range(1, num_pkt+1):
        if i in acked_seq:
            upper += "o"
        else:
            upper += "_"
        if LHS == i and RHS == i:
            lower += "|"
        elif LHS == i:
            lower += "["
        elif RHS == i:
            lower += "]"
        else:
            lower += " "
    if RHS == num_pkt+1:
        lower += "]"
    print("Packet sending progress:")
    print(upper)
    print(lower)
    print("LHS: {}, RHS: {}".format(LHS, RHS))
'''
def switchy_main(net):
    my_intf = net.interfaces()
    mymacs = [intf.ethaddr for intf in my_intf]
    myips = [intf.ipaddr for intf in my_intf]

    start_time = time.time()
    num_reTX = 0
    num_TO = 0
    total_byte = 0
    good_byte = 0

    # read file
    filename = "lab_6/blaster_params.txt"
    with open(filename) as f:
        content = f.readlines()
    params = content[0].split()
    blastee_ip = params[1]
    num_pkt = int(params[3])
    len_payload = int(params[5])
    SW =  int(params[7])
    timeout = float(params[9])
    recv_timeout = float(params[11])

    LHS = RHS = 1       
    LHS_lastmove = time.time()
    acked_seq = []
    packet = {}       #seq is key

    reTX_finish = True #用于标志一轮重发是否完成
    last_reTX = -1 #最后一个重发的包的位置

    while True:
        #draw_progress(num_pkt, acked_seq, LHS, RHS)
 
        # 结束,打印状态
        if LHS == num_pkt+1:
            total_TX_time = time.time() - start_time
            throughput = total_byte/total_TX_time
            goodput = good_byte/total_TX_time
            log_info("Total TX time: {}".format(total_TX_time))
            log_info("Number of reTX: {}".format(num_reTX))
            log_info("Number of coarse TOs: {}".format(num_TO))
            log_info("Throughput: {}".format(throughput))
            log_info("Goodput: {}".format(goodput))
            break

        gotpkt = True
        try:
            timestamp,dev,pkt = net.recv_packet(timeout=0.15)
        except NoPackets:
            log_debug("No packets available in recv_packet")
            gotpkt = False
        except Shutdown:
            log_debug("Got shutdown signal")
            break

        if gotpkt:
            log_debug("I got a packet")
            
            bytes_data = pkt[3].to_bytes()
            seq_num_bytes = bytes_data[:4]
            seq_num = int.from_bytes(seq_num_bytes, byteorder='big')
            #log_info("ACK #{}".format(seq_num))
            
            if seq_num not in acked_seq:
                acked_seq.append(seq_num)
                del packet[seq_num]   
                # 如果LHS已经应答，则移动LHS  
                while LHS in acked_seq: 
                    LHS += 1
                    LHS_lastmove = time.time()  
        
        else:
            log_debug("Didn't receive anything")

            #超时重传
            if LHS < RHS and 1000*(time.time() - LHS_lastmove) >= timeout:        
                if reTX_finish == True: #开启新重传
                    num_TO += 1
                    reTX_finish = False

                if last_reTX == -1 or last_reTX < LHS: #校正位置为LHS  
                    last_reTX = LHS

                # 对于在重传过程中收到ACK的包，直接跳过
                while last_reTX in acked_seq and last_reTX < RHS:
                    last_reTX += 1

                if last_reTX == RHS: #重传完成
                    reTX_finish = True           
                    last_reTX = -1              
                    LHS_lastmove = time.time()     
                    continue

                # 重传
                #log_info("Resend #{}".format(last_reTX))
                net.send_packet("blaster-eth0", packet[last_reTX])
                num_reTX += 1
                total_byte += len_payload
                last_reTX += 1

                while last_reTX in acked_seq and last_reTX < RHS:
                    last_reTX += 1

                if last_reTX == RHS: #重传完成
                    reTX_finish = True           
                    last_reTX = -1              
                    LHS_lastmove = time.time()     
                    continue

            #正常传输
            elif RHS != num_pkt+1 and RHS-LHS+1 < SW:
                new_pkt = Ethernet() + IPv4() + UDP()
                new_pkt[0].src = "10:00:00:00:00:01"
                new_pkt[0].dst = "40:00:00:00:00:02"
                new_pkt[1].src = IPv4Address("192.168.100.1")
                new_pkt[1].dst = IPv4Address(blastee_ip)
                new_pkt[1].protocol = IPProtocol.UDP
                seq_num = RHS
                seq_bytes = seq_num.to_bytes(4, byteorder='big')
                new_pkt.add_header(seq_bytes)

                len_payload_bytes = len_payload.to_bytes(2, byteorder='big')
                new_pkt.add_header(len_payload_bytes)

                payload = (randint(0, 1024)).to_bytes(len_payload, byteorder='big') #随机生成payload
                new_pkt.add_header(payload)
                #log_info("payload: {}".format(payload_bytes))

                packet[seq_num] = new_pkt
                net.send_packet("blaster-eth0", new_pkt)
                #log_info("Send #{}".format(seq_num))
                total_byte += len_payload
                good_byte += len_payload
                RHS += 1
                if RHS >= 1+num_pkt: #防止超限
                    RHS = 1+num_pkt

    net.shutdown()
